<template>
  <div>
    <!-- 面包屑导航区 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item>商品管理</el-breadcrumb-item>
      <el-breadcrumb-item>参数列表</el-breadcrumb-item>
    </el-breadcrumb>
    <!-- 卡片视图 -->
    <el-card>
      <el-alert
        show-icon
        title="注意：只允许为第三层级的商品设置相关参数！"
        type="warning"
        :closable="false"
      >
      </el-alert>
      <!-- 选择商品分类区域 -->
      <el-row class="cat_opt">
        <el-col>
          <span>请选择商品分类：</span>
          <!-- 选择上商品分类的级联选择框 -->
          <el-cascader
            :options="cateList"
            :props="cateProps"
            v-model="selectedCateKeys"
            @change="handleChange"
          ></el-cascader>
        </el-col>
      </el-row>
      <!-- tab栏标签区域 -->
      <el-tabs v-model="activeTabName" @tab-click="handleTabClick">
        <!-- 添加动态参数的面板 -->
        <el-tab-pane label="动态参数" name="many">
          <el-button
            type="primary"
            size="mini"
            :disabled="isBtnDisabled"
            @click="showAddDialog"
            >添加参数</el-button
          >
          <!-- 动态参数表格 -->
          <el-table :data="manyTableList" border stripe>
            <!-- 展开行 -->
            <el-table-column type="expand">
              <template slot-scope="scope">
                <el-tag
                  v-for="(item, i) in scope.row.attr_vals"
                  :key="i"
                  closable
                  @close="deleteThisValue(i, scope.row)"
                  >{{ item }}</el-tag
                >
                <el-input
                  class="input-new-tag"
                  v-if="scope.row.inputVisible"
                  v-model="scope.row.inputValue"
                  ref="saveTagInput"
                  size="small"
                  @keyup.enter.native="handleInputConfirm(scope.row)"
                  @blur="handleInputConfirm(scope.row)"
                >
                </el-input>
                <el-button
                  v-else
                  class="button-new-tag"
                  size="small"
                  @click="showInput(scope.row)"
                  >+ New Tag</el-button
                >
              </template>
            </el-table-column>
            <!-- 索引列 -->
            <el-table-column type="index"></el-table-column>
            <el-table-column
              label="参数名称"
              prop="attr_name"
            ></el-table-column>
            <el-table-column label="操作">
              <template slot-scope="scope">
                <el-button
                  type="primary"
                  icon="el-icon-edit"
                  size="mini"
                  @click="showEditDialog(scope.row)"
                  >编辑</el-button
                >
                <el-button
                  type="danger"
                  icon="el-icon-delete"
                  size="mini"
                  @click="deleteThisData(scope.row.attr_id)"
                  >删除</el-button
                >
              </template>
            </el-table-column>
          </el-table>
        </el-tab-pane>
        <!-- 添加静态属性的面板 -->
        <el-tab-pane label="静态属性" name="only">
          <el-button
            type="primary"
            size="mini"
            :disabled="isBtnDisabled"
            @click="showAddDialog"
            >添加属性</el-button
          >
          <!--静态属性表格 -->
          <el-table :data="onlyTableList" border stripe>
            <!-- 展开行 静态属性的展开行内需要渲染、添加、删除的逻辑和动态参数中完全相同，所以直接复制动态参数中的展开行内代码过来就行-->
            <el-table-column type="expand">
              <template slot-scope="scope">
                <el-tag
                  v-for="(item, i) in scope.row.attr_vals"
                  :key="i"
                  closable
                  @close="deleteThisValue(i, scope.row)"
                  >{{ item }}</el-tag
                >
                <el-input
                  class="input-new-tag"
                  v-if="scope.row.inputVisible"
                  v-model="scope.row.inputValue"
                  ref="saveTagInput"
                  size="small"
                  @keyup.enter.native="handleInputConfirm(scope.row)"
                  @blur="handleInputConfirm(scope.row)"
                >
                </el-input>
                <el-button
                  v-else
                  class="button-new-tag"
                  size="small"
                  @click="showInput(scope.row)"
                  >+ New Tag</el-button
                >
              </template>
            </el-table-column>
            <!-- 索引列 -->
            <el-table-column type="index"></el-table-column>
            <el-table-column
              label="属性名称"
              prop="attr_name"
            ></el-table-column>
            <el-table-column label="操作">
              <template slot-scope="scope">
                <el-button
                  type="primary"
                  icon="el-icon-edit"
                  size="mini"
                  @click="showEditDialog(scope.row)"
                  >编辑</el-button
                >
                <el-button
                  type="danger"
                  icon="el-icon-delete"
                  size="mini"
                  @click="deleteThisData(scope.row.attr_id)"
                  >删除</el-button
                >
              </template>
            </el-table-column>
          </el-table>
        </el-tab-pane>
      </el-tabs>
    </el-card>
    <!-- 添加信息的对话框 -->
    <el-dialog
      :title="activeTabName == 'many' ? '添加动态参数' : '添加静态属性'"
      :visible.sync="addDialogVisible"
      width="50%"
      @close="addDialogClosed"
    >
      <el-form
        :model="addForm"
        :rules="addFormRules"
        ref="addFormRef"
        label-width="100px"
      >
        <el-form-item :label="titleText" prop="attr_name">
          <el-input type="text" v-model="addForm.attr_name"></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="addDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="addDataToServer">确 定</el-button>
      </span>
    </el-dialog>
    <!-- 编辑信息的对话框 -->
    <el-dialog
      :title="activeTabName == 'many' ? '修改动态参数' : '修改静态属性'"
      :visible.sync="editDialogVisible"
      width="50%"
      @close="editDialogClosed"
    >
      <!-- 规则的校验都使用跟添加信息的对话框中一样的就可以 -->
      <el-form
        :model="editForm"
        :rules="addFormRules"
        ref="editFormRef"
        label-width="100px"
      >
        <el-form-item :label="titleText" prop="attr_name">
          <el-input type="text" v-model="editForm.attr_name"></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="editDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="editDataToServer">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
export default {
  data() {
    return {
      // 商品分类列表
      cateList: [],
      //  级联选择框的配置对象
      cateProps: {
        value: 'cat_id',
        label: 'cat_name',
        children: 'children',
      },
      // 级联选择器双向绑定的数组（用于存储所选项的id）
      selectedCateKeys: [],
      // 被激活的tab页标签名称
      activeTabName: 'many',
      // 存放请求来的动态参数的数据
      manyTableList: [],
      // 存放请求来的静态属性的数据
      onlyTableList: [],
      addDialogVisible: false,
      editDialogVisible: false,
      // 添加动态参数或静态属性时保存的数据
      addForm: {
        attr_name: '',
        attr_sel: '',
        attr_vals: '',
      },
      // 编辑动态参数或静态属性时保存的数据
      editForm: {
        attr_id: 0,
        attr_name: '',
        attr_sel: '',
      },
      // 验证规则
      addFormRules: {
        attr_name: [
          { required: true, message: '此项不能为空！', trigger: 'blur' },
        ],
      },
      // 控制新增tag是按钮(false)还是文本框(true)
      inputVisible: false,
      // tag变文本框后输入的内容
      inputValue: '',
    }
  },
  created() {
    //   获取所有的商品分类列表
    this.getCateList()
  },
  methods: {
    //   获取所有的商品分类列表
    async getCateList() {
      const { data: res } = await this.$http.get('categories')
      if (res.meta.status !== 200) {
        return this.$message.error('获取商品分类列表数据失败！')
      }
      this.cateList = res.data
    },
    // 级联选择器选项有变动时触发--value默认是所选项的数组
    handleChange() {
      // 只允许选择三级分类，直接判断保存当前所选项的数组length是不是3即可
      if (this.selectedCateKeys.length !== 3) {
        // 不等于3就清空双向绑定的数组数据
        this.selectedCateKeys.length = 0
        // 前台页面属性和参数的渲染依赖于本地数据many/onlyTableList
        // 如果先选择了三级项目，这两个数组会保存对应的数据
        // 如果后边又选择了二级或一级：1、所选项目数组长度不是3，计算属性cateID的值是null；2、不会再调用getParamsData()，数组内数据也就还是第一次的---也就是下面的属性、参数都还是上一次的残留，就算进行编辑也无法提交，因为cateID是null。
        // 为了避免这个问题，需要将存储many和only的数组清空，让前台页面没得数据可以渲染
        this.manyTableList = []
        this.onlyTableList = []
        return this.$message.warning('只允许选择第三层级商品分类！')
      }
      // 每次选择变化后数组就会变，定义了计算属性catID用于存储变化后的第三等级商品id
      this.getParamsData()
    },
    // tab标签点击事件的函数--不同的tab标签对应的请求数据不同
    handleTabClick() {
      this.getParamsData()
      console.log(this.activeTabName)
    },
    // 根据商品的选择变化或tab面板切换的变化来发起请求--获取商品参数列表数据
    async getParamsData() {
      // 根据所选分类的id以及当前所选择的tab标签面板来发起对应的请求
      const { data: res } = await this.$http.get(
        `categories/${this.cateID}/attributes`,
        { params: { sel: this.activeTabName } }
      )
      if (res.meta.status !== 200) {
        return this.$message.error('获取参数列表失败!')
      }
      console.log(res.data)
      // 获取到数据之后，将存储详细数据的attr_vals转换为一个数组，供tag结构渲染
      res.data.forEach((item) => {
        // 在转换之前先判断是否为空，如果为空''它的split也会生成含有一个空字符串的数组，也就会有一个空tag结构出现
        item.attr_vals = item.attr_vals == '' ? [] : item.attr_vals.split(' ')
        // 由于新增tag绑定了inputValue，其按钮或框的状态根据inputVisible决定，为了让每行的新增tag状态独立，而不是点一个就会影响到所有的，这里给它的不绑定属性做成私有化(做成这一行数据对象的属性)
        item.inputVisible = false
        item.inputValue = ''
      })
      // 根据当前页签来决定将请求的数据存放到哪个数组中
      if (this.activeTabName == 'many') {
        this.manyTableList = res.data
      } else {
        this.onlyTableList = res.data
      }
    },
    // 显示添加属性、参数的对话框
    showAddDialog() {
      this.addDialogVisible = true
    },
    // 显示编辑属性、参数的对话框
    showEditDialog(data) {
      console.log(data)
      this.editForm.attr_name = data.attr_name
      this.editForm.attr_id = data.attr_id
      this.editDialogVisible = true
    },
    // 关闭添加信息的对话框
    addDialogClosed() {
      this.$refs.addFormRef.resetFields()
      this.addForm.attr_name = ''
      this.addForm.attr_sel = ''
      this.addForm.attr_vals = ''
    },
    // 关闭修改信息的对话框
    editDialogClosed() {
      this.$refs.editFormRef.resetFields()
      this.editForm.attr_name = ''
      this.editForm.attr_id = 0
      this.editForm.attr_sel = ''
    },
    // 添加对话框的确定按钮
    addDataToServer() {
      this.$refs.addFormRef.validate(async (valid) => {
        if (!valid) {
          return false
        } else {
          const { data: res } = await this.$http.post(
            `categories/${this.cateID}/attributes`,
            {
              attr_name: this.addForm.attr_name,
              attr_sel: this.activeTabName,
            }
          )
          if (res.meta.status !== 201) {
            this.$message.error('添加失败！')
          } else {
            this.$message.success('添加成功！')
            this.getParamsData()
          }
          this.addDialogVisible = false
        }
      })
    },
    // 编辑对话框的确定按钮
    editDataToServer() {
      this.$refs.editFormRef.validate(async (valid) => {
        if (!valid) {
          return false
        } else {
          const { data: res } = await this.$http.put(
            `categories/${this.cateID}/attributes/${this.editForm.attr_id}`,
            {
              attr_name: this.editForm.attr_name,
              attr_sel: this.activeTabName,
            }
          )
          if (res.meta.status !== 200) {
            return this.$message.error('修改数据失败！')
          } else {
            this.$message.success('更新数据成功！')
            this.getParamsData()
            this.editDialogVisible = false
          }
        }
      })
    },
    // 删除动态参数或静态属性---都是根据商品id和参数属性id进行删除
    async deleteThisData(attrId) {
      const flag = await this.$confirm(
        '此操作将永久删除该数据, 是否继续?',
        '提示',
        {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning',
        }
      ).catch((err) => err)
      if (flag !== 'confirm') {
        return this.$message.info('已取消删除操作')
      } else {
        const { data: res } = await this.$http.delete(
          `categories/${this.cateID}/attributes/${attrId}`
        )
        if (res.meta.status !== 200) {
          return this.$message.error('删除数据失败！')
        } else {
          this.getParamsData()
          return this.$message.success('已删除此数据！')
        }
      }
    },
    // 点击tag按钮转换为文本输入框
    showInput(rowData) {
      rowData.inputVisible = true
      // element-ui官方文档中让这个input自动获取焦点
      // 利用了nextTick：页面元素被重新渲染之后才会执行这里的回调函数(如果直接给它加focus是不行的，因为还没从button转为input时，input还没有出现，这时候加focus徒劳)
      this.$nextTick((_) => {
        this.$refs.saveTagInput.$refs.input.focus()
      })
    },
    // tag变input后按下了回车或者失去焦点都会触发
    handleInputConfirm(rowData) {
      // 判断是否输入了有效内容而不是空字符串
      if (rowData.inputValue.trim().length === 0) {
        rowData.inputValue = ''
        rowData.inputVisible = false
        return
      } else {
        // 有效则发起添加请求--注意！发请求前得先把添加的参数追加到attr_vals数组中，再把这个数组转为字符串作为最新数据向服务器发送请求
        rowData.attr_vals.push(rowData.inputValue.trim())
        this.saveAttrValues(rowData)
      }
      rowData.inputValue = ''
      rowData.inputVisible = false
    },
    // 保存参数数据(新增时、删除后更新时都需要重复代码，所以这里做以封装)
    async saveAttrValues(rowData) {
      const { data: res } = await this.$http.put(
        `categories/${this.cateID}/attributes/${rowData.attr_id}`,
        {
          attr_name: rowData.attr_name.trim(),
          attr_sel: rowData.attr_sel,
          attr_vals: rowData.attr_vals.join(' '),
        }
        // (注意服务器返回的attr_vals是字符串，但是返回来后被前端改为数组，所以发起请求时这个数据还得变回字符串)
      )
      if (res.meta.status !== 200) {
        this.$message.error('参数项修改失败！')
      } else {
        this.$message.success('参数项修改成功！')
      }
    },
    // 删除动态参数或静态属性
    async deleteThisValue(index, rowData) {
      const result = await this.$confirm(
        '确定要删除此数据吗？删除后不可恢复。',
        '提示',
        {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning',
        }
      ).catch((err) => err)
      if (result !== 'confirm') {
        this.$message.info('已取消该删除操作！')
      } else {
        console.log(rowData)
        // 更新前端本地数据--将要删除的从数组中删除掉
        rowData.attr_vals.splice(index, 1)
        console.log(rowData.attr_vals)
        // 将跟新后的数据保存到数据库中
        this.saveAttrValues(rowData)
      }
    },
  },
  computed: {
    // 如果按钮需要被禁用，则返回true，否则返回false-如果还没有选择分类应该禁用按钮
    isBtnDisabled() {
      if (this.selectedCateKeys.length !== 3) {
        return true
      }
      return false
    },
    // 当前选中的商品分类的id
    cateID() {
      if (this.selectedCateKeys.length == 3) {
        return this.selectedCateKeys[2]
      }
      return null
    },
    titleText() {
      if (this.activeTabName == 'many') {
        return '参数名称'
      } else {
        return '属性名称'
      }
    },
  },
}
</script>

<style lang="less" scoped>
.cat_opt {
  margin: 15px 0;
}
.el-tag {
  margin-left: 10px;
}
.input-new-tag {
  width: 120px;
}
.button-new-tag,
.input-new-tag {
  margin-left: 10px;
}
</style>